/*
 * Copyright (c) zero. 2022-2023. All rights reserved.
 *
 */

package com.zero.tool.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zero.tool.string.StringUtils;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Map;




/**
 * @Author lin
 * @Description
 * @Date 8:35 PM 2023/4/9

 
 **/
public class JacksonUtil {

    private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);


    private static final ObjectMapper objectMapper;



    static {
        objectMapper = new ObjectMapper();
        // 对象的所有字段全部列入，还是其他的选项，可以忽略null等
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //包装器
        objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        // 设置Date类型的序列化及反序列化格式
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 忽略未知属性，防止json字符串中存在，而java对象中不存在对应属性的情况出现错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }



    /**
  * @Author lin
  * @Description 输入要序列化成字符串的对象，可以是object或者list、map、jsonNode等各种形式，返回序列化后的String
  * @Date 8:29 PM 2023/4/9
  * @Param [object]
  * @return java.lang.String
  **/
    public static String object2Json(Object object) {
        String json = "";
        try {
            json = objectMapper.writeValueAsString(object);
        } catch (IOException e) {
            logger.error("serializable object2Json error{}", e.getMessage());
        }
        return json;
    }

    /**
     * @Author lin
     * @Description json字符串反序列为java对象
     * @Date 8:29 PM 2023/4/9
     * @Param [jsonStr, objClass]
     * @return T
     **/
    public static <T> T json2Object(String jsonStr, Class<T> objClass) {
        T t = null;
        try {
            t = objectMapper.readValue(jsonStr, objClass);
        } catch (IOException e) {
            logger.error("serializable json2Object error {}", e.getMessage());
        }
        return t;
    }

    /**
     * @Author lin
     * @Description json数组反序列话为java的List<T>对象
     * @Date 8:30 PM 2023/4/9
     * @Param [jsonArr, objClass]
     * @return java.util.List<T>
     **/

    public static <T> List<T> jsonArr2ObjList(String jsonArr, Class<T> objClass) {
        List<T> list = Collections.emptyList();
        try {
            list = objectMapper.readValue(jsonArr, new TypeReference<List<T>>() {});
        } catch (IOException e) {
            logger.error("serializable jsonArr2ObjList error{}",e.getMessage());
        }
        return list;
    }

    /**
     * @Author lin
     * @Description json反序列化为map对象
     * @Date 8:31 PM 2023/4/9
     * @Param [jsonStr]
     * @return java.util.Map
     **/

    public static <K,V> Map<K,V> json2Map(String jsonStr){
        Map<K,V> map = Collections.EMPTY_MAP;
        try {
            map = objectMapper.readValue(jsonStr, new TypeReference<Map<K,V>>(){});
        } catch (IOException e) {
            logger.error("serializable json2Map error{}",e.getMessage());
        }
        return map;
    }

    /**
     * @Author lin
     * @Description json反序列化为JsonNode对象
     * @Date 8:44 PM 2023/4/9
     * @Param [jsonStr]
     * @return com.fasterxml.jackson.databind.JsonNode
     **/

    public static JsonNode json2JsonNode(String jsonStr){
        JsonNode jsonNode = null;
        try{
            jsonNode = objectMapper.readTree(jsonStr);
        } catch (IOException e) {
            logger.error("serializable json2JsonNode error{}",e.getMessage());
        }
        return jsonNode;
    }

    /**
     * @Author lin
     * @Description java对象转ObjectNode
     * @Date 9:30 PM 2023/4/9
     * @Param [obj]
     * @return com.fasterxml.jackson.databind.JsonNode
     **/

    public static JsonNode object2JsonNode(Object obj){
        JsonNode jsonNode = null;
        try{
            jsonNode = objectMapper.valueToTree(obj);
        } catch (IllegalArgumentException e) {
            logger.error("serializable object2JsonNode error{}",e.getMessage());
        }
        return jsonNode;
    }

    /**
     * @Author lin
     * @Description jsonNode对象转为Obj
     * @Date 9:37 PM 2023/4/9
     * @Param [jsonNode, tClass]
     * @return T
     **/

    public static <T> T jsonNode2Object(JsonNode jsonNode, Class<T> tClass) {
        T t = null;
        try {
            t = objectMapper.treeToValue(jsonNode, tClass);
        } catch (JsonProcessingException e) {
            logger.error("serializable jsonNode2Object error{}", e.getMessage());
        }
        return t;
    }

    /**
     * @Author lin
     * @Description 使用序列化方式进行类型转换
     * @Date 1:38 AM 2023/4/11
     * @Param [object, tClass]
     * @return T
     **/

    public static <T> T convert(Object object,Class<T> tClass){
        T t = null;
        try{
            t = objectMapper.readValue(object2Json(object),tClass);
        } catch (IOException e) {
            logger.error("convert object error{}", e.getMessage());
        }
        return t;
    }

    public static ObjectNode getObjectNode(){
        return objectMapper.createObjectNode();
    }

    public static ArrayNode getJsonArrayNode(){
        return objectMapper.createArrayNode();
    }


    public static JsonParser getJsonParser(String jsonStr){
        try {
            return new JsonFactory().createParser(jsonStr);
        } catch (IOException e) {
            logger.error("getJsonParser error{}", e.getMessage());
            return null;
        }
    }


    /**
     * @Author lin
     * @Description 只做了针对基础数据类型的转换
     * @Date 10:56 PM 2023/4/9
     * @Param [jonStr, tClass]
     * @return T
     **/

    public static <T> T parserJson2Object(String jonStr,Class<T> tClass){
        JsonParser jsonParser = JacksonUtil.getJsonParser(jonStr);
        try {
            T t = tClass.newInstance();
            while(!jsonParser.isClosed()){
                JsonToken jsonToken = jsonParser.nextToken();
                if(JsonToken.FIELD_NAME.equals(jsonToken)){
                    String fieldName = jsonParser.getCurrentName();
                    jsonParser.nextToken();
                    Field[] fields = tClass.getDeclaredFields();
                    for (Field field : fields) {
                        if(field.getName().equals(fieldName)){
                            Method method = tClass.getMethod("set" + StringUtils.firstCharUpperCase(field.getName()),field.getType());
                            method.setAccessible(true);
                            Class<?> type = field.getType();
                            if(String.class.equals(type)){
                                method.invoke(t,jsonParser.getValueAsString());
                            }
                            if(Long.class.equals(type)){
                                method.invoke(t,jsonParser.getValueAsLong());
                            }

                        }
                    }
                }
            }
            return t;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    @SneakyThrows
    public static JsonGenerator getJsonGenerator(){
        return objectMapper.getJsonFactory().createJsonGenerator(System.out, JsonEncoding.UTF8);
    }

}
